<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图片管理 - 信院数字人后台</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <style>
        :root{--color-primary:#003366;--color-danger:#d7000f;--color-border:#d0d0d0;--color-row-hover:#f5f7fa;}
        body{font-family:"Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;background:#f3f4f6;font-size:14px;}
        .sidebar{width:240px;background:#001529;color:#c7d0d9;display:flex;flex-direction:column;}
        .sidebar .logo{height:64px;display:flex;align-items:center;justify-content:center;font-size:18px;font-weight:600;background:#002140;color:#fff;padding:0 16px;}
        .sidebar .logo img{width:40px;height:40px;border-radius:50%;margin-right:12px;object-fit:contain;background:#fff;padding:2px;}
        .sidebar .menu a{display:block;padding:12px 24px;font-size:14px;transition:background .2s;}
        .sidebar .menu a:hover,.sidebar .menu a.active{background:#1890ff;color:#fff;}
        .topbar{height:64px;background:#fff;border-bottom:1px solid var(--color-border);padding:0 24px;display:flex;align-items:center;justify-content:space-between;}
        .btn{display:inline-flex;align-items:center;justify-content:center;padding:6px 16px;font-size:14px;border:1px solid var(--color-border);background:#fff;cursor:pointer;transition:all .2s;border-radius:4px;}
        .btn-primary{background:var(--color-primary);color:#fff;border-color:var(--color-primary);}
        .btn-primary:hover{background:#004080;}
        .btn-danger{color:var(--color-danger);border-color:var(--color-danger);}
        .btn-danger:hover{background:var(--color-danger);color:#fff;}
        .data-table{width:100%;border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid var(--color-border);}
        .data-table thead{background-color:#f5f7fa;color:#333;}
        .data-table th,.data-table td{padding:12px 16px;border-bottom:1px solid var(--color-border);border-right:1px solid var(--color-border);text-align:left;word-break:break-all;line-height:1.4;vertical-align:middle;}
        .data-table th:last-child,.data-table td:last-child{border-right:none;}
        .data-table tr:hover{background-color:var(--color-row-hover);}
        .data-table th.id-col{width:60px;}.data-table th.preview-col{width:100px;}.data-table th.name-col{width:140px;}.data-table th.description-col{width:200px;}.data-table th.keywords-col{width:200px;}.data-table th.time-col{width:140px;}.data-table th.action-col{width:100px;text-align:center;}
        .data-table td.action-col{text-align:center;}
        .action-btn{display:inline-block;width:28px;height:28px;line-height:28px;text-align:center;border-radius:4px;margin:0 4px;cursor:pointer;transition:all .2s;color:#666;border:1px solid transparent;}
        .action-btn:hover{background-color:#f0f0f0;border-color:#ddd;}
        .action-btn.edit{color:#1890ff;}.action-btn.edit:hover{background-color:#e6f7ff;border-color:#bae7ff;}
        .action-btn.delete{color:#ff4d4f;}.action-btn.delete:hover{background-color:#fff2f0;border-color:#ffccc7;}
        .preview-img{width:80px;height:56px;object-fit:cover;border-radius:4px;border:1px solid #eee;}
        .modal-mask{position:fixed;inset:0;background:rgba(0,0,0,.45);display:flex;align-items:center;justify-content:center;z-index:999;opacity:0;pointer-events:none;transition:opacity .3s;}
        .modal-mask.show{opacity:1;pointer-events:auto;}
        .modal-box{background:#fff;width:640px;max-width:90vw;max-height:90vh;overflow:auto;display:flex;flex-direction:column;border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,0.15);}
        .modal-header{padding:16px 24px;border-bottom:1px solid var(--color-border);font-size:16px;font-weight:600;}
        .modal-footer{padding:12px 24px;border-top:1px solid var(--color-border);text-align:right;}
        .form-input{width:100%;padding:7px 11px;border:1px solid var(--color-border);font-size:14px;transition:border-color .2s;border-radius:4px;}
        .form-input:focus{border-color:var(--color-primary);outline:none;box-shadow:0 0 0 2px rgba(0,51,102,.2);}
        .pagination{font-size:14px;display:flex;align-items:center;gap:8px;}
        .pagination .btn:disabled{opacity:.6;cursor:not-allowed;}

        /* 分页栏固定底部样式 */
        main {
            padding-bottom: 60px !important; /* 预留分页栏高度，防止内容被遮挡 */
        }
        #page {
            position: fixed;
            bottom: 0;
            left: 0;
            right: 0;
            background: white;
            z-index: 10; /* 确保在内容上层 */
            border-top: 1px solid var(--color-border);
            box-shadow: 0 -2px 8px rgba(0,0,0,0.05); /* 可选：添加底部阴影增强视觉 */
        }
    </style>
</head>
<body class="flex h-screen overflow-hidden">
<aside class="sidebar">
    <div class="logo"><img src="/logo/logo.jpg" alt="logo" onerror="this.src='https://picsum.photos/40/40?random=logo';this.style.background='#fff';">信院数字人后台</div>
    <nav class="menu flex-1 pt-4">
        <a href="/admin/usersManage.html"><i class="fa fa-user-o mr-2"></i>用户管理</a>
        <a href="/admin/postsManage.html"><i class="fa fa-comments-o mr-2"></i>言论详情</a>
        <a href="/admin/imagesManage.html" class="active"><i class="fa fa-image mr-2"></i>图片管理</a>
        <a href="/admin/filesManage.html"><i class="fa fa-file-o mr-2"></i>文件管理</a>
    </nav>
</aside>

<section class="flex-1 flex flex-col">
    <header class="topbar">
        <div class="text-base font-medium">图片管理</div>
        <div class="flex items-center gap-4"><span class="text-sm">管理员</span><img src="/logo/guanliyuan.png" class="w-8 h-8 rounded-full"></div>
    </header>

    <main class="flex-1 overflow-y-auto p-6">
        <div class="bg-white border border-gray-200 rounded px-4 py-3 mb-4 flex items-center justify-between">
            <div class="flex items-center gap-4">
                <input id="keyword" type="text" placeholder="请输入图片名称或描述" class="form-input w-64">
                <button id="searchBtn" class="btn btn-primary">查询</button>
                <button id="resetBtn" class="btn">重置</button>
            </div>
            <button id="addBtn" class="btn btn-primary" onclick="showAddModal()"><i class="fa fa-plus mr-1"></i>新增图片</button>
        </div>

        <div class="bg-white rounded overflow-x-auto shadow-sm">
            <table class="data-table min-w-[940px]">
                <thead>
                <tr>
                    <th class="id-col">ID</th><th class="preview-col">预览</th><th class="name-col">图片名称</th>
                    <th class="description-col">描述</th><th class="keywords-col">关键词</th>
                    <th class="time-col">创建时间</th><th class="time-col">更新时间</th><th class="action-col">操作</th>
                </tr>
                </thead>
                <tbody id="list"></tbody>
            </table>
        </div>
    </main>

    <!-- 分页栏从表格下方移出，作为独立区域固定在底部 -->
    <div id="page" class="px-4 py-3 flex items-center justify-between text-sm text-gray-600">
        <div>共 <span id="total">0</span> 条</div>
        <div class="pagination">
            <button id="prev" class="btn">上一页</button>
            <span>第 <span id="curr">1</span> 页 / 共 <span id="pages">1</span> 页</span>
            <button id="next" class="btn">下一页</button>
        </div>
    </div>
</section>

<!-- 新增/编辑模态框 -->
<div id="formModal" class="modal-mask"><div class="modal-box">
    <div class="modal-header"><span id="modalTitle">新增图片</span><button class="btn btn-sm ml-auto" onclick="hideFormModal()"><i class="fa fa-times"></i></button></div>
    <div id="form" class="px-6 py-4 space-y-4">
        <input type="hidden" id="id"><input type="hidden" id="imageBase64">
        <div>
            <label class="block text-sm font-medium mb-1">图片名称 <span class="text-red-600">*</span></label>
            <input type="text" id="imagesName" class="form-input" placeholder="例如：风景（无需输入后缀）" required>
        </div>
        <div>
            <label class="block text-sm font-medium mb-1">上传图片 <span class="text-red-600">*</span></label>
            <div id="uploadBox" class="border border-dashed border-gray-400 rounded p-4 text-center cursor-pointer">
                <input type="file" id="images_file" accept="image/*" class="hidden">
                <i class="fa fa-cloud-upload text-2xl text-gray-400 mb-1"></i><p class="text-gray-500 text-sm">点击或拖拽到此处上传</p>
            </div>
            <div id="preview" class="mt-2 hidden"><img class="max-h-32 rounded border"></div>
            <div id="fullNameTip" class="mt-1 text-sm text-gray-500 hidden"></div>
        </div>
        <div>
            <label class="block text-sm font-medium mb-1">图片描述</label>
            <textarea id="description" rows="3" class="form-input"></textarea>
        </div>
        <div>
            <label class="block text-sm font-medium mb-1">关键词 <span class="text-red-600">*</span></label>
            <input type="text" id="keywords" class="form-input" placeholder="多个关键词用逗号分隔" required>
        </div>
    </div>
    <div class="modal-footer">
        <button type="button" class="btn" onclick="hideFormModal()">取消</button>
        <button type="button" id="saveBtn" class="btn btn-primary">保存</button>
    </div>
</div></div>

<!-- 删除确认框 -->
<div id="delModal" class="modal-mask"><div class="modal-box max-w-sm">
    <div class="modal-header">删除确认</div>
    <div class="p-6 text-center text-sm text-gray-700">此操作不可撤销，确定删除？</div>
    <div class="modal-footer">
        <button class="btn" onclick="hideDelModal()">取消</button>
        <button id="delConfirm" class="btn btn-danger">删除</button>
    </div>
</div></div>

<script>
    /* ---------- 工具 ---------- */
    const $ = q => document.querySelector(q);
    const modalForm = $('#formModal'), modalDel = $('#delModal');
    let currPage = 1, pageSize = 6, delId = 0, totalPages = 1;
    let currEditingRow = null;   // 缓存编辑行原始数据

    /* ① 把「文件名」拼成 /imagesAdmin/文件名 即可访问 */
    function convertLocalPathToUrl(path) {
        if (!path) return '';
        if (path.startsWith('http')) return path;
        return '/imagesAdmin/' + path.replace(/^.*[\\/]/, '');
    }

    /* ② 通用 fetch */
    async function request(url, option = {}) {
        const headers = { 'Content-Type': 'application/json', ...option.headers };
        const body = option.body && typeof option.body === 'object' ? JSON.stringify(option.body) : option.body;

        try {
            const res = await fetch(url, {
                ...option,
                headers,
                body,
                credentials: 'include'  // 关键：携带认证信息
            });

            // 检查响应状态
            if (!res.ok) {
                const errorText = await res.text();
                console.error('请求失败:', res.status, errorText);
                throw new Error(`请求失败 (${res.status}): ${errorText}`);
            }

            const contentType = res.headers.get('content-type');
            return contentType && contentType.includes('application/json')
                ? res.json()
                : res.text();
        } catch (error) {
            console.error('请求异常:', error);
            throw error;
        }
    }
    /* ③ 文件 → base64（无头） */
    function fileToBase64(file) {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.onload = e => resolve(e.target.result.split(',')[1]);
            reader.onerror = reject;
            reader.readAsDataURL(file);
        });
    }

    /* ④ 加载表格 + 分页控件 */
    async function loadTable() {
        const kw = $('#keyword').value.trim();
        const params = new URLSearchParams({ pageNum: currPage, pageSize, keyword: kw });
        try {
            const res = await request('/api/admin/images?' + params);
            const list = res.records || [], total = res.total || 0;
            totalPages = Math.max(1, Math.ceil(total / pageSize));
            let html = '';
            list.forEach(r => {
                const url = convertLocalPathToUrl(r.imagesUrl);
                html += `<tr>
                    <td class="id-col">${r.id}</td>
                    <td class="preview-col"><img src="${url}" class="preview-img" onerror="this.src='https://picsum.photos/80/56?random=${r.id}'"></td>
                    <td class="name-col">${r.imagesName}</td>
                    <td class="description-col">${r.description || ''}</td>
                    <td class="keywords-col">${(r.keywords || []).join(', ')}</td>
                    <td class="time-col">${r.startTime || '-'}</td>
                    <td class="time-col">${r.updateTime || '-'}</td>
                    <td class="action-col">
                        <span class="action-btn edit" title="编辑" onclick="editRow(${r.id})"><i class="fa fa-pencil"></i></span>
                        <span class="action-btn delete" title="删除" onclick="delRow(${r.id})"><i class="fa fa-trash-o"></i></span>
                    </td>
                </tr>`;
            });
            $('#list').innerHTML = html || '<tr><td colspan="8" class="text-center text-gray-400 py-8">暂无数据</td></tr>';
            $('#total').textContent = total;
            $('#curr').textContent = currPage;
            $('#pages').textContent = totalPages;
            $('#prev').disabled = currPage === 1;
            $('#next').disabled = currPage === totalPages;
        } catch (e) { alert('加载表格失败：' + e.message); }
    }

    /* 分页按钮 */
    $('#prev').onclick = () => {
        if (currPage > 1) { currPage--; loadTable(); }
    };
    $('#next').onclick = () => {
        if (currPage < totalPages) { currPage++; loadTable(); }
        else { alert('已经是最后一页啦！'); }
    };

    /* ⑤ 新增/编辑/删除弹窗控制 */
    function showAddModal() {
        $('#id').value = '';
        $('#imagesName').value = $('#description').value = $('#keywords').value = $('#images_file').value = '';
        $('#preview').classList.add('hidden'); $('#fullNameTip').classList.add('hidden');
        $('#modalTitle').textContent = '新增图片';
        currEditingRow = null;
        modalForm.classList.add('show');
    }
    function hideFormModal() { modalForm.classList.remove('show'); }
    function hideDelModal() { modalDel.classList.remove('show'); }

    /* ⑥ 编辑（带图片回显） */
    async function editRow(id) {
        try {
            const row = await request(`/api/admin/images/${id}`);
            $('#id').value = row.id;
            const [pure] = splitNameAndExtension(row.imagesName);
            $('#imagesName').value = pure;
            $('#description').value = row.description || '';
            $('#keywords').value = (row.keywords || []).join(', ');
            $('#fullNameTip').textContent = `完整名称（不可修改）：${row.imagesName}`;
            $('#fullNameTip').classList.remove('hidden');
            const url = convertLocalPathToUrl(row.imagesUrl);
            $('#preview img').src = url;
            $('#preview').classList.remove('hidden');
            $('#images_file').value = '';
            $('#modalTitle').textContent = '编辑图片';
            currEditingRow = row;   // 缓存原记录
            modalForm.classList.add('show');
        } catch (e) { alert('加载编辑数据失败：' + e.message); }
    }

    /* ⑦ 拆分名称 & 后缀 */
    function splitNameAndExtension(full) {
        if (!full) return ['', ''];
        const idx = full.lastIndexOf('.');
        return idx > 0 ? [full.slice(0, idx), full.slice(idx + 1)] : [full, ''];
    }

    /* ⑧ 保存（重新上传时回传 imagesUrl） */
    $('#saveBtn').onclick = async () => {
        try {
            const id = $('#id').value.trim();
            const inputName = $('#imagesName').value.trim();
            const desc = $('#description').value.trim();
            const kw = $('#keywords').value.trim();
            const file = $('#images_file').files[0];
            if (!inputName) return alert('图片名称不能为空');
            if (!kw) return alert('关键词不能为空');
            if (!id && !file) return alert('请选择要上传的图片');

            const keywords = kw.split(',').map(s => s.trim()).filter(Boolean);
            const body = {
                imagesName: '',
                description: desc,
                keywords,
                imagesFile: null,
                imagesUrl: null
            };

            const isEdit = !!id;
            if (file) {
                // 重新上传：生成新文件名 + 计算新访问地址
                const ext = file.name.split('.').pop().toLowerCase();
                body.imagesName = `${inputName}.${ext}`;
                body.imagesFile = [await fileToBase64(file)];
                body.imagesUrl = '/imagesAdmin/' + `${inputName}.${ext}`; // 关键：回传新地址
            } else {
                // 未上传：保留原名 + 原地址
                const [, oldExt] = splitNameAndExtension(currEditingRow.imagesName);
                body.imagesName = oldExt ? `${inputName}.${oldExt}` : inputName;
                body.imagesUrl = currEditingRow.imagesUrl;
            }

            await request(isEdit ? `/api/admin/images/${id}` : '/api/admin/images', {
                method: isEdit ? 'PUT' : 'POST',
                body
            });
            hideFormModal(); loadTable();
            alert(isEdit ? '图片编辑成功' : '图片新增成功');
        } catch (e) { alert('保存失败：' + e.message); }
    };

    /* ⑨ 文件选择 & 拖拽 & 名称提示 */
    $('#images_file').onchange = async (e) => {
        const file = e.target.files[0];
        if (!file) { $('#preview').classList.add('hidden'); $('#fullNameTip').classList.add('hidden'); return; }
        const base64 = await fileToBase64(file);
        $('#preview img').src = `data:${file.type};base64,${base64}`;
        $('#preview').classList.remove('hidden');
        const input = $('#imagesName').value.trim();
        const ext = file.name.split('.').pop().toLowerCase();
        $('#fullNameTip').textContent = `即将上传的完整名称：${input ? `${input}.${ext}` : file.name}`;
        $('#fullNameTip').classList.remove('hidden');
    };
    $('#imagesName').oninput = () => {
        const input = $('#imagesName').value.trim();
        const file = $('#images_file').files[0];
        if (!file) return;
        const ext = file.name.split('.').pop().toLowerCase();
        $('#fullNameTip').textContent = `即将上传的完整名称：${input}.${ext}`;
        $('#fullNameTip').classList.remove('hidden');
    };

    /* ⑩ 删除 */
    function delRow(id) { delId = id; modalDel.classList.add('show'); }
    $('#delConfirm').onclick = async () => {
        try {
            await request(`/api/admin/images/${delId}`, { method: 'DELETE' });
            hideDelModal(); loadTable(); alert('删除成功');
        } catch (e) { alert('删除失败：' + e.message); }
    };

    /* ⑪ 搜索 / 重置 */
    $('#searchBtn').onclick = () => { currPage = 1; loadTable(); };
    $('#resetBtn').onclick = () => { $('#keyword').value = ''; currPage = 1; loadTable(); };

    /* ⑫ 上传区域点击 & 拖拽 */
    const uploadBox = $('#uploadBox');
    uploadBox.onclick = () => $('#images_file').click();
    uploadBox.ondragover = e => { e.preventDefault(); uploadBox.classList.add('border-primary', 'bg-blue-50'); };
    uploadBox.ondragleave = () => uploadBox.classList.remove('border-primary', 'bg-blue-50');
    uploadBox.ondrop = e => { e.preventDefault(); uploadBox.classList.remove('border-primary', 'bg-blue-50'); if (e.dataTransfer.files[0]) { $('#images_file').files = e.dataTransfer.files; e.target.dispatchEvent(new Event('change')); } };

    /* ⑬ 初始化 */
    window.onload = () => { loadTable(); };
</script>
</body>
</html>
